#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/select.h>
 
#define PORT 8080
#define BACKLOG 10
#define BUFFER_SIZE 1024
 
int main() {
    int listen_fd, conn_fd, max_fd;
    struct sockaddr_in server_addr, client_addr;
    socklen_t client_len = sizeof(client_addr);
    fd_set read_fds;
    struct timeval timeout;
    char buffer[BUFFER_SIZE];
 
    // 创建监听 socket
    listen_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (listen_fd < 0) {
        perror("socket");
        exit(EXIT_FAILURE);
    }
 
    // 设置服务器地址和端口
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(PORT);
 
    // 绑定 socket 到地址和端口
    if (bind(listen_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
        perror("bind");
        close(listen_fd);
        exit(EXIT_FAILURE);
    }
 
    // 开始监听连接
    if (listen(listen_fd, BACKLOG) < 0) {
        perror("listen");
        close(listen_fd);
        exit(EXIT_FAILURE);
    }
 
    // 初始化文件描述符集合
    FD_ZERO(&read_fds);
    FD_SET(listen_fd, &read_fds);
 
    // 设置最大文件描述符和超时时间
    max_fd = listen_fd;
    timeout.tv_sec = 5; // 5秒超时
    timeout.tv_usec = 0;
 
    while (1) {
        // 复制文件描述符集合，因为 select 会修改它
        fd_set read_fds_copy = read_fds;
 
        // 调用 select 函数
        int ret = select(max_fd + 1, &read_fds_copy, NULL, NULL, &timeout);
        if (ret < 0) {
            perror("select");
            close(listen_fd);
            exit(EXIT_FAILURE);
        } else if (ret == 0) {
            printf("Timeout occurred! No data...\n");
            continue; // 超时，没有数据可读，继续循环
        }
 
        // 检查监听 socket 是否有新的连接
        if (FD_ISSET(listen_fd, &read_fds_copy)) {
            conn_fd = accept(listen_fd, (struct sockaddr *)&client_addr, &client_len);
            if (conn_fd < 0) {
                perror("accept");
                continue;
            }
 
            // 将新的连接添加到文件描述符集合中
            FD_SET(conn_fd, &read_fds);
            if (conn_fd > max_fd) {
                max_fd = conn_fd; // 更新最大文件描述符
            }
 
            printf("Accepted new connection from %s:%d\n",
                   inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
        }
 
        // 检查其他已连接的客户端是否有数据可读
        for (int fd = 0; fd <= max_fd; fd++) {
            if (FD_ISSET(fd, &read_fds_copy) && fd != listen_fd) {
                int bytes_read = read(fd, buffer, BUFFER_SIZE - 1);
                if (bytes_read < 0) {
                    perror("read");
                    close(fd); // 关闭出现错误的客户端连接
                    FD_CLR(fd, &read_fds); // 从文件描述符集合中移除该连接
                } else if (bytes_read == 0) {
                    // 客户端关闭连接
                    printf("Client %d disconnected\n", fd);
                    close(fd);
                    FD_CLR(fd, &read_fds);
                } else {
                    // 处理接收到的数据（这里只是简单地打印出来）
                    buffer[bytes_read] = '\0'; // 确保字符串以空字符结尾
                    printf("Received from client %d: %s\n", fd, buffer);
 
                    // 回显数据给客户端（可选）
                    write(fd, buffer, bytes_read);
                }
            }
        }
    }
 
    // 关闭监听 socket
    close(listen_fd);
    return 0;
}